//
//  DefaultAlertController.swift
//  SwiftCode
//
//  Created by 于虎拴 on 2022/7/27.
//

import Foundation
import UIKit
import SnapKit

struct AlertInfo {
  let title: String
  let message: String?
  let confirmText: String?
  let cancelText: String?
  
  /// extension for custom
  let image: UIImage?
  let attributedMessage: NSAttributedString?
  
  /// system
  init(title: String,
       message: String? = nil,
       confirmText: String? = "确定",
       cancelText: String? = "取消") {
    self.title = title
    self.message = message
    self.confirmText = confirmText
    self.cancelText = cancelText
    self.image = nil
    self.attributedMessage = nil
  }
  
  /// custom
  init(title: String, message: String? = nil,
       confirmText: String? = "确定",
       cancelText: String? = "取消",
       image: UIImage? = nil,
       attributedMessage: NSAttributedString? = nil) {
    self.title = title
    self.message = message
    self.confirmText = confirmText
    self.cancelText = cancelText
    self.image = image
    self.attributedMessage = attributedMessage
  }
}

public struct AlertAction {
  typealias Handler = (AlertAction) -> Void
  
  let title: String
  let style: UIAlertAction.Style
  let handler: Handler?
  
  init(title: String, style: UIAlertAction.Style, handler: Handler? = nil) {
    self.title = title
    self.style = style
    self.handler = handler
  }
}

public struct AlertTheme {
  public static let titleTextColor = UIColor(hex: 0x222222)
  public static let cancelTextColor = UIColor(hex: 0x222222)
  public static let defaultBackgroundColor = UIColor(hex: 0xFF7210)
}

final class DefaultAlertController: UIViewController {
  private var actions: [AlertAction] = []
  
  private var size: CGSize = .init(width: 270, height: 0)
  private let padding: UIEdgeInsets = .init(top: 20, left: 20, bottom: 24, right: 20)
  private let buttonHeight: CGFloat = 44
  private let buttonFontSize: CGFloat = 15
  private let imageSize = CGSize(width: 45, height: 45)
  
  init(image: UIImage?,
       title: String,
       message: String?, attributedMessage: NSAttributedString?,
       preferredStyle: UIAlertController.Style = .alert) {
    super.init(nibName: nil, bundle: nil)
    modalPresentationStyle = .overCurrentContext
    modalTransitionStyle = .crossDissolve
    
    // initData
    titleLabel.text = title
    if let attributedMessage = attributedMessage {
      messageLabel.attributedText = attributedMessage
    } else {
      messageLabel.text = message
    }
    
    // initView
    view.backgroundColor = .black.withAlphaComponent(0.1)
    view.addSubview(backgroud)
    
    backgroud.snp.makeConstraints { make in
      make.width.equalTo(size.width)
      make.center.equalToSuperview()
    }
    
    backgroud.addSubview(titleLabel)
    if let image = image {
      imageView.image = image
      backgroud.addSubview(imageView)
      imageView.snp.makeConstraints { make in
        make.top.equalToSuperview().offset(padding.top)
        make.size.equalTo(imageSize)
        make.centerX.equalToSuperview()
      }
      titleLabel.snp.makeConstraints { make in
        make.top.equalTo(imageView.snp.bottom).offset(padding.top - 2)
        make.leading.equalToSuperview().inset(padding.left)
        make.trailing.equalToSuperview().inset(padding.right)
      }
    } else {
      titleLabel.snp.makeConstraints { make in
        make.top.equalToSuperview().offset(padding.top)
        make.leading.equalToSuperview().inset(padding.left)
        make.trailing.equalToSuperview().inset(padding.right)
      }
    }
    
    [messageLabel, buttonStack].forEach { backgroud.addSubview($0) }
    
    messageLabel.snp.makeConstraints { make in
      make.top.equalTo(titleLabel.snp.bottom).offset(10)
      make.leading.equalToSuperview().inset(padding.left)
      make.trailing.equalToSuperview().inset(padding.right)
    }
    
    buttonStack.snp.makeConstraints { make in
      make.top.equalTo(messageLabel.snp.bottom).offset(15)
      make.leading.equalToSuperview().inset(padding.left)
      make.trailing.equalToSuperview().inset(padding.right)
      make.bottom.equalToSuperview().inset(padding.bottom)
    }
  }
  
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  func addAction(_ action: AlertAction) {
    let button: UIButton
    switch action.style {
    case .cancel:
      button = cancelButton()
    case UIAlertAction.Style.default:
      button = defaultButton()
    case .destructive:
      button = destructiveButton()
    @unknown default:
      fatalError("error")
    }
    button.setTitle(action.title, for: .normal)

    button.tag = actions.count
    actions.append(action)
    button.addTarget(self, action: #selector(onClick(sender:)), for: .touchUpInside)

    buttonStack.addArrangedSubview(button)
    button.snp.makeConstraints { make in
      make.height.equalTo(buttonHeight)
    }
    if actions.count > 2 {
      buttonStack.axis = .vertical
    }
  }
  
  override var shouldAutorotate: Bool {
    return false
  }
  
  @objc func onClick(sender: UIButton) {
    let action = actions[sender.tag]
    dismiss(animated: true) {
      action.handler?(action)
    }
  }
  
  private lazy var backgroud: UIView = {
    let bg = UIView()
    bg.backgroundColor = .white
    bg.layer.cornerRadius = 16.0
    bg.layer.masksToBounds = true
    return bg
  }()
  
  private lazy var imageView: UIImageView = {
    let imageView = UIImageView()
    return imageView
  }()
  
  private lazy var titleLabel: UILabel = {
    let label = UILabel()
    label.textColor = AlertTheme.titleTextColor
    label.font = .systemFont(ofSize: 15, weight: .medium)
    label.textAlignment = .center
    label.numberOfLines = 0
    return label
  }()
  
  private lazy var messageLabel: UILabel = {
    let label = UILabel()
    label.textColor = .secondaryLabel
    label.font = .systemFont(ofSize: 12)
    label.textAlignment = .center
    label.numberOfLines = 0
    return label
  }()
  
  private lazy var buttonStack: UIStackView = {
    let stack = UIStackView()
    stack.axis = .horizontal
    stack.distribution = .fillEqually
    stack.spacing = 16
    return stack
  }()
  
  private func cancelButton() -> UIButton {
    let button = UIButton()
    button.setTitleColor(AlertTheme.cancelTextColor, for: .normal)
    button.titleLabel?.font = .systemFont(ofSize: buttonFontSize, weight: .medium)
//    button.backgroundColor = .mainBackgroundColor
    button.layer.cornerRadius = buttonHeight / 2
    return button
  }
  
  private func defaultButton() -> UIButton {
    let button = UIButton()
    button.setTitleColor(UIColor.white, for: .normal)
    button.titleLabel?.font = .systemFont(ofSize: buttonFontSize, weight: .medium)
    button.backgroundColor = AlertTheme.defaultBackgroundColor
    button.layer.cornerRadius = buttonHeight / 2
    return button
  }
  
  private func destructiveButton() -> UIButton {
    let button = UIButton()
    button.setTitleColor(UIColor.red, for: .normal)
    button.titleLabel?.font = .systemFont(ofSize: buttonFontSize, weight: .medium)
//    button.backgroundColor = .mainBackgroundColor
    button.layer.cornerRadius = buttonHeight / 2
    return button
  }
}
